/*
 * @Author       : mark
 * @Date         : 2020-06-17
 * @copyleft Apache 2.0
 */ 

#include "sqlconnpool.h"
using namespace std;

SqlConnPool::SqlConnPool() 
    : use_count_(0), 
      free_count_(0) {
    
}

SqlConnPool* SqlConnPool::Instance() {
    //单例模式, 使用静态变量只创建一个实例
    static SqlConnPool connPool;
    return &connPool;
}

void SqlConnPool::Init(const char* host, int port,const char* user, 
                       const char* pwd, const char* db_name, int conn_size = 10) {
    assert(conn_size > 0);
    //创建conn_size个数据库连接放入连接池
    for (int i = 0; i < conn_size; i++) {
        MYSQL *sql = nullptr;
        sql = mysql_init(sql);
        if (!sql) {
            LOG_ERROR("MySql init error!");
            assert(sql);
        }
        sql = mysql_real_connect(sql, host, user, pwd, db_name, port, nullptr, 0);
        if (!sql) {
            LOG_ERROR("MySql Connect error!");
        }
        conn_que_.push(sql);
    }
    max_conn_ = conn_size;
    sem_init(&sem_, 0, max_conn_);
}

MYSQL* SqlConnPool::GetConn() {
    MYSQL *sql = nullptr;
    
    if(conn_que_.empty()){
        LOG_WARN("SqlConnPool busy!");
        return nullptr;
    }
    sem_wait(&sem_);
    {
        lock_guard<mutex> locker(mtx_);
        sql = conn_que_.front();
        conn_que_.pop();
    }
    return sql;
}

void SqlConnPool::FreeConn(MYSQL* sql) {
    assert(sql);
    lock_guard<mutex> locker(mtx_);
    conn_que_.push(sql);
    sem_post(&sem_);
}

void SqlConnPool::ClosePool() {
    lock_guard<mutex> locker(mtx_);
    while(!conn_que_.empty()) {
        auto item = conn_que_.front();
        conn_que_.pop();
        mysql_close(item);
    }
    mysql_library_end();        
}

int SqlConnPool::GetFreeConnCount() {
    lock_guard<mutex> locker(mtx_);
    return conn_que_.size();
}

SqlConnPool::~SqlConnPool() {
    ClosePool();
}
